Всичко в 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