Всичко в Python е обект. Това включва:
type() и dir()dir() ни позволява да видим атрибутите, на които един метод отговаря. type() пък ни връща класът на своя аргумент като обект.
text = ["Ni!", "Shrubbery", "Knights"] print type(text), tupe(text) == tuple print dir(text)
<type 'list'>
Всъщност, представете си следното.
.__dict__.. те се търсят в този речник. Ако не бъдат намерени се извиква __getattr__ в случай че е дефиниран.
class Foo(object): pass
f = Foo()
f.spam, f.eggs = "Spam", "Eggs"
print "f.__dict__:", f.__dict__
print "f.spam, f.eggs:", f.spam, f.eggs
f.__dict__ = {'larodi' : "Larodi"}
print "f.larodi: " + f.larodi
print "f.spam: " + f.spam
f.__dict__: {'eggs': 'Eggs', 'spam': 'Spam'}
f.spam, f.eggs: Spam Eggs
f.larodi: Larodi
Всъщност, нещата са една идея по-сложни.
__class__. Последния също е обект.obj.name се изпълнява функцията __getattribute__(obj, name) на obj.__class__.object. Тя е имплементирана както обяснихме два слайда по-рано.Полежението при класовете е идентично. Просто имате по-интересен синтаксис за дефиниране на __dict__.
class Foo(object):
spam = "Eggs"
def bar(self): pass
print Foo.__dict__.keys()
['__module__', 'bar', 'spam', '__dict__', '__weakref__', '__doc__']
При извикване на obj.name:
name не присъства в obj.__dict__. Ако да - връща се тази стойностobj.__class__ има такъв атрибут в своя __dict__. Ако да и атрибута не е функция, той се връща.obj.__class__ е функцията mth се връща нещо като lambda *args: mth(obj, *args). Всъщност, това е малко по-особен тип bound method.
class Person(object):
def __init__(self, name): self.name = name
def sayHi(self): print "Hi, I am", self.name
def wave(self): print self.name, "is waving"
mityo = Person("Mityo")
print mityo.sayHi
print Person.sayHi
mityo.sayHi()
Person.sayHi(mityo)
<bound method Person.sayHi of <__main__.Person object at 0x2a955d71d0>>
<unbound method Person.sayHi>
Hi, I am Mityo
Hi, I am Mityo
class Person(object):
def __init__(self, name): self.name = name
def sayHi(self): print "Hi, I am", self.name
def wave(self): print self.name, "is waving"
class Hacker(object):
def sayHi(self): print self.name, "has been hacked by ninjas"
def slash(self): print "Slash! Slash! Slash!"
mityo = Person("Mityo")
mityo.sayHi()
mityo.wave()
mityo.__class__ = Hacker
mityo.sayHi()
mityo.slash()
mityo.wave()
Hi, I am Mityo
Mityo is waving
Mityo has been hacked by ninjas
Slash! Slash! Slash!
type() revisitedМоже да разглеждате type и като конструктор за нови класове. Следните дефиниции са еквивалентни:
class Base(object): pass
class Derived(Base):
count = 0
def foo(self): return "The foo of %s" % self
Derived = type("Derived", (Base,), {
'count': 0,
'foo': lambda self: "The foo of %s" % self
})
Всъщност, всички класове дефинирани с class са инстанции на type.
[Metaclasses] are deeper magic than 99% of the users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).
— Tim Peters
Всеки клас е инстанция или на type, или на друг тип, който го наследява. Това се нарича „клас на класа“ или „метаклас“.
Meta (from Greek: after, beyound, with) is a prefix used in English in order to indicate a concept which is an abstraction from another concept, used to complete or add to the latter.
Определянето на метакласа става чрез промяна на атрибута __metaclass__ на класа.
class Foo(object):
__metaclass__ = type
class BarMeta(type):
pass
class Bar(object):
__metaclass__ = BarMeta
Обекта поставен в __metaclass__ трябва да дефинира оператор (), вземащ три аргументи - име на клас, n-орка от родители и речник с атрибути. Трябва да връща нов клас на базата на тези аргументи (така прави type). Съответно, може или да си направите наследник на type или да дадете функция с такава сигнатура.
import re
def Namer(clname, bases, cdict):
for name in [_ for _ in cdict.keys() if re.search('[a-z][A-Z]', _)]:
new_name = re.sub('([a-z])([A-Z])', r'\1_\2', name).lower()
cdict[new_name] = cdict[name]
del cdict[name]
return type(clname, bases, cdict)
class Person(object):
__metaclass__ = Namer
theNumberOfPersons = 1
def __init__(self, name): self.name = name
def getMyNameNow(self): return self.name
p = Person("Mityo")
print p.get_my_name_now()
print Person.the_number_of_persons
print p.getMyNameNow()
from types import FunctionType
class selfless(type):
def __new__(cls, name, bases, classDict):
for attr in classDict:
if not isinstance(classDict[attr], FunctionType): continue
classDict[attr] = selflessWrapper(classDict[attr])
return type.__new__(cls, name, bases, classDict)
def selflessWrapper(func):
def wrapper(self, *args, **kwargs):
hadSelf, oldSelf = func.func_globals.has_key('self'), func.func_globas.get('self')
func.func_globals['self'] = self
returnValue = func(*args, **kwargs)
if hadSelf:
func.func_globals['self'] = oldSelf
else:
del func.func_globals['self']
return returnValue
wrapper.func_name = func.func_name + "_wrapper"
return wrapper