pythoncharm有哪些奇技淫巧

2025-04-28 11:20:52
推荐回答(1个)
回答1:

1. 元类(metaclass)
PyPy的源码里有个pair和extendabletype
"""
Two magic tricks for classes:
class X:
__metaclass__ = extendabletype
...
# in some other file...
class __extend__(X):
... # and here you can add new methods and class attributes to X
Mostly useful together with the second trick, which lets you build
methods whose 'self' is a pair of objects instead of just one:
class __extend__(pairtype(X, Y)):
attribute = 42
def method((x, y), other, arguments):
...
pair(x, y).attribute
pair(x, y).method(other, arguments)
This finds methods and class attributes based on the actual
class of both objects that go into the pair(), with the usual
rules of method/attribute overriding in (pairs of) subclasses.
For more information, see test_pairtype.
"""

class extendabletype(type):
"""A type with a syntax trick: 'class __extend__(t)' actually extends
the definition of 't' instead of creating a new subclass."""
def __new__(cls, name, bases, dict):
if name == '__extend__':
for cls in bases:
for key, value in dict.items():
if key == '__module__':
continue
# XXX do we need to provide something more for pickling?
setattr(cls, key, value)
return None
else:
return super(extendabletype, cls).__new__(cls, name, bases, dict)

def pair(a, b):
"""Return a pair object."""
tp = pairtype(a.__class__, b.__class__)
return tp((a, b)) # tp is a subclass of tuple

pairtypecache = {}

def pairtype(cls1, cls2):
"""type(pair(a,b)) is pairtype(a.__class__, b.__class__)."""
try:
pair = pairtypecache[cls1, cls2]
except KeyError:
name = 'pairtype(%s, %s)' % (cls1.__name__, cls2.__name__)
bases1 = [pairtype(base1, cls2) for base1 in cls1.__bases__]
bases2 = [pairtype(cls1, base2) for base2 in cls2.__bases__]
bases = tuple(bases1 + bases2) or (tuple,) # 'tuple': ultimate base
pair = pairtypecache[cls1, cls2] = extendabletype(name, bases, {})
return pair

先说extendabletype。嘛 其实注释已经说得听明白了,就是一个C#里面的partial class的Python实现。
然后是pair和pairtype。pairtype就是根据两个类创建一个新的类,这个类继承自使用这两个类的基类构造的pairtype(有点绕……)或者tuple。
有啥用呢?可以拿来实现multimethod。
class __extend__(pairtype(int, int)):
def foo((x, y)):
print 'int-int: %s-%s' % (x, y)

class __extend__(pairtype(bool, bool)):
def bar((x, y)):
print 'bool-bool: %s-%s' % (x, y)

pair(False, True).foo() # prints 'int-int: False, True'
pair(123, True).foo() # prints 'int-int: 123, True'
pair(False, True).bar() # prints 'bool-bool: False, True'
pair(123, True).bar() # Oops, no such method

好像这个例子里元类只是个打辅助的角色,好玩的都在那个pair里……
再换一个。
class GameObjectMeta(type):
def __new__(mcls, clsname, bases, _dict):
for k, v in _dict.items():
if isinstance(v, (list, set)):
_dict[k] = tuple(v) # mutable obj not allowed

cls = type.__new__(mcls, clsname, bases, _dict)
all_gameobjects.add(cls)
for b in bases:
game_objects_hierarchy.add((b, cls))

return cls

@staticmethod
def _dump_gameobject_hierarchy():
with open('/dev/shm/gomap.dot', 'w') as f:
f.write('digraph {\nrankdir=LR;\n')
f.write('\n'.join([
'"%s" -> "%s";' % (a.__name__, b.__name__)
for a, b in game_objects_hierarchy
]))
f.write('}')

def __setattr__(cls, field, v):
type.__setattr__(cls, field, v)
if field in ('ui_meta', ):
return

log.warning('SetAttr: %s.%s = %s' % (cls.__name__, field, repr(v)))

这个是从我写的三国杀游戏中提取的一段代码(点我签名上的链接)。大意就是把class上所有可变的容器都换成不可变的,然后记录下继承关系。
曾经被这个问题坑过,class上的值是全局共享的,逻辑代码一不小心修改了class上的值,单机测试的时候是测不出来的,然后放到线上……就悲剧了……当时绞尽脑汁没有想到是这个问题硬生生的回滚了……发现了问题之后就加上了这个东西,不允许修改class上的东西。
记录下继承关系是为了画类图。
还有就是常用的做数据注入
metadata = {}

def gen_metafunc(_for):
def metafunc(clsname, bases, _dict):
meta_for = getattr(_for, clsname)
meta_for.ui_meta = UIMetaDescriptor()
if meta_for in metadata:
raise Exception('%s ui_meta redefinition!' % meta_for)

metadata[meta_for] = _dict

return metafunc

from gamepack.thb import characters

__metaclass__ = gen_metafunc(characters.sakuya)

class Sakuya:
# 于是这个就不是类了, 而是作为数据存到了metadata这个dict里
char_name = u'十六夜咲夜'
port_image = 'thb-portrait-sakuya'
figure_image = 'thb-figure-sakuya'
miss_sound_effect = 'thb-cv-sakuya_miss'
description = (
u'|DB完全潇洒的PAD长 十六夜咲夜 体力:4|r\n\n'
u'|G月时计|r:|B锁定技|r,准备阶段开始时,你执行一个额外的出牌阶段。\n\n'
u'|G飞刀|r:你可以将一张装备牌当【弹幕】使用或打出。按此法使用的【弹幕】无距离限制。\n\n'
u'|DB(画师:小D@星の妄想乡,CV:VV)|r'
)

Ruby党不要喷,我知道你们可以做的更优雅……

2. Python沙盒逃逸

刷新三观的Python代码
3. PEP302 New Import Hook
最近在把刚才提到的纯Python游戏向Unity引擎上移植。
玩过Unity的就会知道,Unity的游戏的资源都是打包在一起的,没有单独的文件,Python解释器就不高兴了……于是写了import hook,用Unity提供的API来读py文件。
# -*- coding: utf-8 -*-

# -- stdlib --
import imp
import sys

# -- third party --
# -- own --
from clr import UnityEngine, WarpGateController

# -- code --

class UnityResourceImporter(object):
known_builtin = (
'sys',
'imp',
'cStringIO',
'gevent_core',
'gevent_ares',
'gevent_util',
'gevent_semaphore',
'msgpack_packer',
'msgpack_unpacker',
'UnityEngine',
)

def __init__(self, bases, unity_loader):
self.bases = bases
self.last_fullname = ''
self.last_text = ''
self.last_ispkg = False
self.unity_load = unity_loader

def find_module(self, fullname, path=None):
if fullname in sys.modules:
return self

head = fullname.split('.')[0]
if head in self.known_builtin:
return None

rst = self.do_load_module(fullname)
if rst:
self.last_text, self.last_ispkg = rst
self.last_fullname = fullname
return self
else:
return None

def load_module(self, fullname):
if fullname in sys.modules:
return sys.modules[fullname]

if fullname != self.last_fullname:
self.find_module(fullname)

try:
code = self.last_text
ispkg = self.last_ispkg

mod = sys.modules.setdefault(fullname, imp.new_module(fullname))
mod.__file__ = "" % fullname
mod.__loader__ = self

if ispkg:
mod.__path__ = []
mod.__package__ = fullname
else:
mod.__package__ = fullname.rpartition('.')[0]

co = compile(code, mod.__file__, 'exec')
exec(co, mod.__dict__)

return mod
except Exception as e:
UnityEngine.Debug.LogError('Error importing %s %s' % (fullname, e))
raise ImportError(e)

def do_load_module(self, fullname):
fn = fullname.replace('.', '/')

asset = self.try_load(fn + '.py')
if asset is not None:
return asset, False

asset = self.try_load(fn + '/__init__.py')
if asset is not None:
return asset, True

def try_load(self, filename):
for b in self.bases:
asset = self.unity_load(b + filename)
if asset is not None:
return asset

return None

sys.meta_path.append(UnityResourceImporter([
'Python/THBattle/',
'Python/Site/',
'Python/Stdlib/',
], WarpGateController.GetTextAsset))

需要的extension module都静态编译到解释器里了,所以没考虑。
4. 可以批量执行操作的list
class BatchList(list):
def __getattribute__(self, name):
try:
list_attr = list.__getattribute__(self, name)
return list_attr
except AttributeError:
pass

return list.__getattribute__(self, '__class__')(
getattr(i, name) for i in self
)

def __call__(self, *a, **k):
return list.__getattribute__(self, '__class__')(
f(*a, **k) for f in self
)

class Foo(object):
def __init__(self, v):
self.value = v

def foo(self):
print 'Foo!', self.value

foo = Foo(1)
foo.foo() # Foo! 1

foos = BatchList(Foo(i) for i in xrange(10))
foos.value # BatchList([0, 1, 2, 3, ..., 9])
foos.foo() # 你能猜到的

这个其实不算很黑魔法了,只是感觉很好用也有些危险,所以放上来。
暂时就想到这么多了,以后发现了再补。